from django.db import DatabaseError
from django.db.transaction import atomic
from django.http import HttpRequest, HttpResponse
from django.utils.decorators import method_decorator
from django.views.decorators.cache import cache_page
from rest_framework.decorators import api_view, authentication_classes
from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet

from polls.models import Subject, Teacher, User
from polls.serializers import SubjectSerializer, SubjectSimpleSerializer, TeacherSerializer
from polls.utils import LoginRequiredAuthentication


# class HotSubjectView(ListAPIView):
#     queryset = Subject.objects.filter(is_hot=True)
#     serializer_class = SubjectSerializer


# 通过method_decorator装饰器可以将原本装饰函数的装饰器cache_page加到类中指定的方法上
@method_decorator(decorator=cache_page(timeout=3600, cache='api'), name='list')
class SubjectViewSet(ModelViewSet):
    """
    学科视图集
    list:
        获取所有学科信息
    retrieve:
        获取指定学科信息
    create:
        创建新学科
    update:
        更新指定学科信息
    destroy:
        删除指定学科
    """
    queryset = Subject.objects.all()
    serializer_class = SubjectSerializer
    # authentication_classes = (LoginRequiredAuthentication, )


# @api_view(('GET', ))
# # @cache_page(timeout=3600, cache='api')
# def show_subjects(request: HttpRequest) -> HttpResponse:
#     """获取学科数据"""
#     # caches['api'].get('...')
#     # caches['api'].set('...', ...)
#     redis_cli = get_redis_connection(alias='api')
#     data = redis_cli.get('vote:polls:subjects')
#     if data:
#         data = ujson.loads(data)
#     else:
#         queryset = Subject.objects.all()
#         data = SubjectSerializer(queryset, many=True).data
#         redis_cli.set('vote:polls:subjects', ujson.dumps(data), ex=3600)
#     return Response({'subjects': data})


@api_view(('GET', ))
def show_teachers(request: HttpRequest) -> HttpResponse:
    """获取指定学科老师数据"""
    sno = int(request.GET['sno'])
    subject = Subject.objects.only('name').get(no=sno)
    sub_seri = SubjectSimpleSerializer(subject)
    queryset = Teacher.objects.filter(subject__no=sno).defer('subject')
    tea_seri = TeacherSerializer(queryset, many=True)
    return Response({'subject': sub_seri.data, 'teachers': tea_seri.data})


@api_view(('GET', ))
@authentication_classes((LoginRequiredAuthentication, ))
def praise_or_criticize(request: HttpRequest) -> HttpResponse:
    """投票"""
    try:
        user = User.objects.only('counter').get(no=request.user.no)
        if user.counter > 0:
            tno = int(request.GET['tno'])
            teacher = Teacher.objects.get(no=tno)
            user.counter -= 1
            if request.path.startswith('/praise'):
                teacher.good_count += 1
                count = teacher.good_count
            else:
                teacher.bad_count += 1
                count = teacher.bad_count
            with atomic():
                teacher.save()
                user.save()
            data = {'code': 10000, 'message': '投票成功', 'count': count}
        else:
            data = {'code': 10002, 'message': '每天只能投5票'}
    except (KeyError, ValueError, DatabaseError, Teacher.DoesNotExist, User.DoesNotExist):
        data = {'code': 10001, 'message': '投票失败'}
    return Response(data)


@api_view(('GET', ))
@authentication_classes((LoginRequiredAuthentication, ))
def get_stat_data(request: HttpRequest) -> HttpResponse:
    teachers = Teacher.objects.all()\
        .only('name', 'good_count', 'bad_count')\
        .order_by('-good_count')[:10]
    x_data = [teacher.name for teacher in teachers]
    y1_data = [teacher.good_count for teacher in teachers]
    y2_data = [teacher.bad_count for teacher in teachers]
    return Response({'xData': x_data, 'y1Data': y1_data, 'y2Data': y2_data})
